package com.shitou.shitoucommons.exception;

import com.shitou.shitoucommons.utils.RespBean;
import com.shitou.shitoucommons.validate.MemberEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.util.HashMap;
import java.util.Map;

/**
 * class detail:
 *
 * @author 石头人
 */
@Slf4j
@SuppressWarnings("all")
@Component
public class ControllerAdviceImpl implements ControllerAdvice {

    private static ControllerAdviceImpl controllerAdvice;

    public static ControllerAdviceImpl controllerAdvice(){
        if ( controllerAdvice == null ){
            return new ControllerAdviceImpl();
        }
        return controllerAdvice;
    }

    /**
     * controller方法中的参数校验失败
     * @param e
     * @return
     */
    @Override
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public RespBean bindingException(MethodArgumentNotValidException e) {
        // 获得所有校验出错的返回集
        BindingResult bindingResult = e.getBindingResult();
        // 循环获得所有校验异常的字段
        Map<String, String> fieldMap = new HashMap<>();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            fieldMap.put(fieldError.getField(), fieldError.getDefaultMessage());
        }
        // 输出错误类以及字段
        int begin = e.getMessage().indexOf("(");
        int end = e.getMessage().indexOf("javax.servlet.http.HttpServletResponse,org.springframework.validation.BindingResult");
        // 返回给前端
        return RespBean.error(MemberEnum.BINDING_EXCEPTION.getCode(),
                MemberEnum.BINDING_EXCEPTION.getMessage()).put("data", fieldMap);
    }


    /**
     *
     * @param nullPointerException
     * @return
     */
    @Override
    @ExceptionHandler(value = NullPointerException.class)
    public RespBean nullPointException(NullPointerException nullPointerException) {
        log.error("空指针异常类型: {},信息: {}", nullPointerException.getClass(),nullPointerException.getMessage());
        nullPointerException.printStackTrace();
        return RespBean.error("不可以不填写信息哦");
    }


    /**
     * 所有的运行时异常，抛出异常
     * @param throwable
     * @return
     */
    @ExceptionHandler(value = Throwable.class)
    @Override
    public RespBean handleException(Throwable throwable) {
        log.error("异常类型: {}, {}, 信息为: {}", throwable.getCause(), throwable.getClass(), throwable.getMessage());
        if ( throwable instanceof RRException){
            RRException rrException = (RRException)throwable;
            return RespBean.error(rrException.getCode(), rrException.getMsg());
        }
        return RespBean.error(MemberEnum.ERROR_EXCEPTION.getCode(),
                throwable.getMessage());
    }


    /**
     * http信息无可读
     * @param exception
     * @return
     */
    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    @Override
    public RespBean httpMessageNotReadAbleException(HttpMessageNotReadableException exception){
        log.error("异常类型: {} 无可读信息: {}", exception.getClass(), exception.getMessage());
        return RespBean.error(MemberEnum.BINDING_EXCEPTION.getCode(), MemberEnum.BINDING_EXCEPTION.getMessage());
    }


    /**
     * 运行时异常
     * @param exceptions
     * @return
     */
    @ExceptionHandler(value = RuntimeException.class)
    @Override
    public RespBean runtimeException(RuntimeException exceptions){
        if ( !exceptions.getMessage().equals("") ){
            log.error("运行时异常 消息为: {}", exceptions.getMessage());
        }
        if ( exceptions instanceof RRException){
            RRException rrException = (RRException) exceptions;
            return RespBean.error(rrException.getCode(), rrException.getMsg());
        }
        return RespBean.error(MemberEnum.BINDING_EXCEPTION.getCode(), MemberEnum.BINDING_EXCEPTION.getMessage());
    }

}
